﻿#Requires AutoHotkey v2.0

SaveToFile()

SaveToFile() {

  BMPFromHwnd(&hBM, 0, A_ScreenWidth, A_ScreenHeight)

  hbm2 := CreateDIBSection(A_ScreenWidth, -A_ScreenHeight)
  CopyHBM(hbm2, hBM)
  DllCall("DeleteObject", "Ptr", hBM)
  hBM := hbm2

  struct := Buffer(ss := (A_PtrSize = 8 ? 104 : 84))
  DllCall("GetObject", "Ptr", hBM, "int", ss, "Ptr", struct)

  address := struct.Ptr + (A_PtrSize = 8 ? 32 : 24)

  size := NumGet(address + 20, 'uint')
  pBits := NumGet(address - A_PtrSize, 'ptr')

  bf := Buffer(14, 0)
  NumPut('short', 0x4D42, bf)
  NumPut('uint', size + 54, bf, 2)
  NumPut('uint', 54, bf, 10)

  f := FileOpen('C:\Users\dkwd\Desktop\1.bmp', "w")
  f.RawWrite(bf, 14)
  f.RawWrite(address, 40)
  f.RawWrite(pBits, size)
  f.Close()

  DllCall("DeleteObject", "Ptr", hBM)
}

CreateDIBSection(w, h)
{
  bi := Buffer(40, 0)

  NumPut('int', 40, bi)
  NumPut('int', w, bi, 4)
  NumPut('int', -h, bi, 8)
  NumPut('short', 1, bi, 12)
  NumPut('short', 24, bi, 14)

  return DllCall("CreateDIBSection", "Ptr", 0, "Ptr", bi
    , "int", 0, "Ptr*", 0, "Ptr", 0, "int", 0)
}


CopyHBM(hBM1, hBM2)
{
  mDC1 := DllCall("CreateCompatibleDC", "Ptr", 0, "Ptr")
  oBM1 := DllCall("SelectObject", "Ptr", mDC1, "Ptr", hBM1, "Ptr")
  mDC2 := DllCall("CreateCompatibleDC", "Ptr", 0, "Ptr")
  oBM2 := DllCall("SelectObject", "Ptr", mDC2, "Ptr", hBM2, "Ptr")
  DllCall("BitBlt", "Ptr", mDC1, "int", 0, "int", 0, "int", A_ScreenWidth, "int", A_ScreenHeight
    , "Ptr", mDC2, "int", 0, "int", 0, "uint", 0xCC0020)
  DllCall("SelectObject", "Ptr", mDC1, "Ptr", oBM1)
  DllCall("DeleteDC", "Ptr", mDC1)
  DllCall("SelectObject", "Ptr", mDC2, "Ptr", oBM2)
  DllCall("DeleteDC", "Ptr", mDC2)
}

BMPFromHwnd(&hBitmap, hwnd, w, h, x := 0, y := 0) {
  hSourceDC := hwnd ? DllCall('GetDC', 'ptr', hwnd) : DllCall('GetDC', 'ptr', 0)
  hMemDC := DllCall("CreateCompatibleDC", "Ptr", 0)
  hBitmap := DllCall("CreateCompatibleBitmap", "ptr", hSourceDC, "int", w, "int", h)
  hOldBitmap := DllCall("SelectObject", "Ptr", hMemDC, "Ptr", hBitmap)
  DllCall("BitBlt", "Ptr", hMemDC, "int", 0, "int", 0, "int", w, "int", h
    , "Ptr", hSourceDC, "int", x, "int", y, "uint", 0xCC0020)
  hOldBitmap := DllCall("SelectObject", "Ptr", hMemDC, "Ptr", hOldBitmap)
  DllCall('DeleteDC', 'ptr', hMemDC)
  DllCall('ReleaseDC', 'int', 0, 'ptr', hSourceDC)
}